#include "kernel.h"
//#include  "global.h"
#include <stdio.h>
#include <unistd.h>

RTX:: RTX(){
	for( int i = 0; i < Num_Proc; i++ )
        {PCB_list[i] = NULL;}
        cur_proc=NULL;
        prev_proc=NULL;
        
        free_env_Q = new MsgEnvQ(Num_MsgEnv);
        timeout_list=new MsgEnvQ();
        for( int i = 0; i < Num_PriorityLevels; i++ ){
            ready_Q[i] = new PCBQ();
        }
        for( int i = 0; i < Num_PriorityLevels; i++ ){
            blk_on_resource_Q[i]=new PCBQ();
        }
        //for( int i = 0; i < Num_PriorityLevels; i++ ){
        //    blk_on_receive_Q[i]=new PCBQ();
        //}
        //printf("(init RTX)size of ready_Q is[%d]\n");
        system_time=0;
        atomic_flag=0;
        send_trace_buffer = new TraceBuffer[TraceBufferSize];
        receive_trace_buffer= new TraceBuffer[TraceBufferSize];
}

void RTX:: initialization(initTable init_table[]){
     /*init_MsgEn*/
    free_env_Q = new MsgEnvQ(Num_MsgEnv);
    Display_Q= new MsgEnvQ;
    /*initialize PCBs*/
    for(int i=0;i<Num_Proc;i++){
        //put the values in init_table into according fields in PCBs
        //printf("PCB %d\n",i+1);
        PCB_list[i]=new PCB;
        PCB_list[i]->next=NULL;
        PCB_list[i]->msgQ=new MsgEnvQ();
        PCB_list[i]->pid=init_table[i].pid;
        PCB_list[i]->priority=init_table[i].priority;
        PCB_list[i]->status=init_table[i].status;
        PCB_list[i]->address=init_table[i].start_address;
        //put into ready queue if it is not an i-proc
        
        if(PCB_list[i]->priority!=I_Process){
            rpq_enqueue(PCB_list[i]);
           // printf("PCB [%d] is in ready queue\n",PCB_list[i]->pid);
        }   
        getcontext(&(PCB_list[i]->proContext));
        PCB_list[i]->proContext.uc_stack.ss_sp = PCB_list[i]->stack;
        PCB_list[i]->proContext.uc_stack.ss_size = StackSize;
        //PCB_list[i]->proContext.uc_stack.ss_flags = 0;
        makecontext(&PCB_list[i]->proContext, PCB_list[i]->address, 0);
      //  printf("context of %d is set\n",PCB_list[i]->pid);
  }

    /*initialize processes*/
    ucontext_t mainContext;
    getcontext(&mainContext);
    
     /*initialize trace buffer*/
      /*already did in RTX()*/
    
            /*switch to current process*/
    cur_proc=rpq_dequeue();
    cur_proc->status=Executing;
    printf("about to switch to first process from main\n");
    swapcontext(&mainContext, &(cur_proc->proContext));
}		 

void RTX::rpq_enqueue(PCB* pcb){
    ready_Q[pcb->priority]->enqueue(pcb);
    printf("enqueue process [%d] to ready queue priority [%d]\n",pcb->pid,pcb->priority);
    return;
}

PCB * RTX::rpq_dequeue(){
    //printf("dequeue from ready queue\n");
    int pri=0;
    PCB * temp=NULL;
    //printf("size of the ready queue is [%d]\n", rpq_getsize());
    while(pri<4){
        if(ready_Q[pri]->getsize()!=0){//not empty
//            printf("before dequeuing priority [%d] has [%d] process in it,"
//                    "head->[%d],tail->[%d]\n",pri,ready_Q[pri]->getsize(),ready_Q[pri]->get_head_id(),ready_Q[pri]->get_tail_id());
            temp=ready_Q[pri]->dequeue();
            //printf("rpq_dequeue returns the pcb with pid  [%d] priority [%d]\n",temp->pid,pri);
//            printf("dequeue process [%d] to from ready queue priority [%d]\n",temp->pid,temp->priority);
//            printf("after dequeuing priority [%d] has [%d] process in it,"
//                    "head->[%d],tail->[%d]\n",pri,ready_Q[pri]->getsize(),ready_Q[pri]->get_head_id(),ready_Q[pri]->get_tail_id());
            return temp;
        }
        else{
            //printf("ready queue priority %d is empty, go to  [%d]\n",pri,pri+1);
            pri++;
        }    
    }
    printf("nothing is in ready queue :(\n");
    return NULL;
}

int RTX::rpq_getsize(){
    int count=0;
    for(int i=0;i<Num_PriorityLevels;i++){
        count+=ready_Q[i]->getsize();
    }
    return count;
}

PCB * RTX::rpq_remqueue(PCB * pcb){
    PCB * temp=ready_Q[pcb->priority]->remqueue(pcb->pid);
    return temp;
}

//void RTX::blkq_enqueue(int blocked_type,PCB * pcb){
int RTX::blkq_enqueue(PCB * pcb){
    //switch(blocked_type){
        //case Blocked_On_Receive:
            //if(ready_Q[2]->head!=NULL && ready_Q[2]->head->next!=NULL){
                //printf("(before blkq_enqueue)right now the ready queue pri 2 head is [%d] and head next is [%d]\n",ready_Q[2]->head->pid,ready_Q[2]->head->next->pid);
            //}
            //printf("(before blkq_enqueue)cur proc is [%d]\n",cur_proc->pid);
            //printf("(before blkq_enqueue)the size of blk_on_receive_Q is [%d] \n",blkq_getsize(Blocked_On_Receive));
            //printf("(before blkq_enqueue)the size of blk_on_resource_Q is [%d] \n",blkq_getsize(Blocked_On_Resource));
            //printf("(before blkq_enqueue)the size of ready_Q is [%d] \n",rpq_getsize());
            //printf("the process is [%d] with priority [%d]\n",pcb->pid,pcb->priority);
            //blk_on_receive_Q[pcb->priority]->enqueue(pcb);
            //blk_on_receive_Q[2]->enqueue(2);
            //printf("(before blkq_enqueue)the size of ready_Q is [%d] \n",rpq_getsize());
           // printf("(after blkq_enqueue)the size of blk_on_receive_Q is [%d] \n",blkq_getsize(Blocked_On_Receive));
             //printf("(after blkq_enqueue)the size of blk_on_resource_Q is [%d] \n",blkq_getsize(Blocked_On_Resource));
            //printf("(before blkq_enqueue)cur proc is [%d]\n",cur_proc->pid);
            //printf("enqueued into blk_on_receive_Q!\n");
            //if(ready_Q[2]->head!=NULL && ready_Q[2]->head->next!=NULL){
           //     printf("(after blkq_enqueue)right now the ready queue pri 2 head is [%d] and head next is [%d]\n",ready_Q[2]->head->pid,ready_Q[2]->head->next->pid);
           // }
          //  break;
       // case Blocked_On_Resource:
            int result=blk_on_resource_Q[pcb->priority]->enqueue(pcb);
            printf("enqueued into blk_on_resource_Q!\n");
            //break;
       // default:
            //cout<<"Error to enqueue to blocked queue!"
        //   return;
    //}
    //cout<<"enqueued to blocked queue!"
    return result;
}

PCB * RTX::blkq_dequeue(){
//PCB * RTX::blkq_dequeue(int blocked_type){
    PCB * temp =NULL;
    int pri=0;
//    switch(blocked_type){
//        case Blocked_On_Receive:
//             while(pri<4){
//                if(blk_on_receive_Q[pri]->getsize()!=0){//not empty
//                        temp=blk_on_receive_Q[pri]->dequeue();                        
//                        return temp;
//                 }
//                else//empty
//                {pri++;} 
//            }            
//            break;
//        case Blocked_On_Resource:            
            while(pri<4){
                if(blk_on_resource_Q[pri]->getsize()!=0){//not empty
                        temp=blk_on_resource_Q[pri]->dequeue();
                        return temp;
                 }
                else//empty
                {pri++;} 
            }
//            break;
//    }
    return temp;
}

PCB* RTX::blkq_remqueue(PCB * pcb){
//PCB* RTX::blkq_remqueue(int blocked_type,PCB * pcb){
    PCB * temp=NULL;
//    switch(blocked_type){
//        case Blocked_On_Receive:
//            temp=blk_on_receive_Q[pcb->priority]->remqueue(pcb->pid);
//            return temp;
//            break;
//        case Blocked_On_Resource:
            temp=blk_on_resource_Q[pcb->priority]->remqueue(pcb->pid);
            return temp;                   
//            break;
//    }
//    return temp;
}

int RTX::blkq_getsize(){
//int RTX::blkq_getsize(int blocked_type){
    int count=0;
//    if(blocked_type==Blocked_On_Receive){
//        for(int i=0;i<Num_PriorityLevels;i++){
//             count+=(blk_on_receive_Q[i]->getsize());
//        }
//    }
//    else if(blocked_type==Blocked_On_Resource){
        for(int i=0;i<Num_PriorityLevels;i++){
             count+=(blk_on_resource_Q[i]->getsize());
        }
//    }
   return count;
}

//void RTX::timeoutq_enqueue(MsgEnv * newNode){
//    
//}

void RTX::timeoutq_enqueue(MsgEnv * newNode){
    MsgEnv* cur=timeout_list->head;
    int size=timeout_list->getsize();
    while (timeout_list->head!=NULL){
             if (timeout_list->getsize()==1){;//if only 1 node
                       if (newNode->num_clock_ticks>timeout_list->head->num_clock_ticks){//code to sort the envelope into the timeout_list
                                newNode->next=cur;
                                timeout_list->head=newNode;
                                size++;
                                return;
                       }
                       else if (newNode->num_clock_ticks<timeout_list->head->num_clock_ticks){
                                cur->next=newNode;
                                timeout_list->tail=newNode;
                                size++;
                                return;
                       }
             }
             else{//more than 1 node
                       MsgEnv* A=timeout_list->head;
                       MsgEnv* B=timeout_list->head->next;
                       if (newNode->num_clock_ticks>=A->num_clock_ticks){//case 1:newnode is greater than first node, so it becomes the new node
                                newNode->next=A;
                                timeout_list->head=newNode;
                                timeout_list->tail=newNode;
                                size++;
                                return;
                       }
                       if(newNode->num_clock_ticks<timeout_list->tail->num_clock_ticks){//case 2: newnode is SMALLER THAN LAST NODE, so it becomes the new tail
                                MsgEnv* temp;
                                temp=timeout_list->tail;
                                temp->next=newNode;
                                timeout_list->tail=newNode;
                                timeout_list->tail=newNode;
                                size++;
                                return;
                       }
                       if (newNode->num_clock_ticks > timeout_list->head->num_clock_ticks && newNode->num_clock_ticks < timeout_list->tail->num_clock_ticks){//case 3:its in the middle, traverse until it fits
                                while(A->next!=NULL){
                                      if(newNode->num_clock_ticks > A->num_clock_ticks && newNode->num_clock_ticks < B->num_clock_ticks){
                                           A->next=newNode;
                                           newNode->next=B;
                                           size++;
                                           return;
                                      }
                                      else{
                                           A=A->next;
                                           B=B->next;
                                      }
                                }
                       }
        }
        
	}
	timeout_list->enqueue(newNode);
	return;
}
/*
 void RTX::timeoutq_enqueue(MsgEnv * newNode){
     printf("timeoutq_enqueue here\n");
    // printf("(before)timeoutq_enqueue head sender is->[%d],tail sender is->[%d]\n",timeout_list->head->sender_pid,timeout_list->tail->sender_pid);
     MsgEnv* A,*B,*temp;
    MsgEnv* highest=timeout_list->head;
    if (timeout_list->head!=NULL){
             if (timeout_list->head->next==NULL){;//if only 1 node
                   if (newNode->num_clock_ticks>timeout_list->head->num_clock_ticks){//code to sort the envelope into the timeout_list
                        newNode->next=highest;
                        timeout_list->head=newNode;
                        timeout_list->size++;
                        return;
                   }
                   else if (newNode->num_clock_ticks<timeout_list->head->num_clock_ticks){
                        highest->next=newNode;
                        timeout_list->tail=newNode;
                        timeout_list->size++;
                        return;
                   }
             }
             else{//more than 1 node
                   A=timeout_list->head;
                   B=timeout_list->head->next;
                   if (newNode->num_clock_ticks>=A->num_clock_ticks){//case 1:newnode is greater than first node, so it becomes the new node
                            newNode->next=A;
                            timeout_list->head=newNode;
                            timeout_list->size++;
                            return;
                   }
                   if(newNode->num_clock_ticks<timeout_list->tail->num_clock_ticks){//case 2: newnode is SMALLER THAN LAST NODE, so it becomes the new tail
                            temp=timeout_list->tail;
                            temp->next=newNode;
                            timeout_list->tail=newNode;
                            timeout_list->size++;
                            return;
                   }
                   if (newNode->num_clock_ticks > timeout_list->head->num_clock_ticks && newNode->num_clock_ticks < timeout_list->tail->num_clock_ticks){//case 3:its in the middle, traverse until it fits
                            while(A->next!=NULL){
                                  if(newNode->num_clock_ticks < A->num_clock_ticks && newNode->num_clock_ticks > B->num_clock_ticks){
                                       newNode->next=A;
                                       timeout_list->head=newNode;
                                       timeout_list->size++;
                                       return;
                                  }
                                  else{
                                       A=A->next;
                                       B=B->next;
                                  }
                            }
                   }
        }
        }
            timeout_list->enqueue(newNode);
            return;
}
 */
//new for time-out


MsgEnv * RTX:: timeoutq_dequeue(){
    
    MsgEnv *A=NULL;
    MsgEnv *B=NULL;
    A=timeout_list->head;
    if (A!=NULL){
        B=A->next;
        if(B==NULL) {
            timeout_list->size--;
            timeout_list->head=NULL;
            timeout_list->tail=NULL;
            return A;
            
        }
    }
    else{
        return NULL;
    }
     printf("time out queue dequeue 1!\n");
     //if(B==NULL)
     while (B->next!=NULL)
    {
        A=A->next;
        B=B->next;
    }
        printf("time out queue dequeue 2!\n");
        //A=NULL;
        if (timeout_list->size==1){
            timeout_list->head=NULL;
            timeout_list->tail=NULL;
        }
        printf("time out queue dequeue 3!\n");
        timeout_list->tail=A;
        B->next=NULL;
        timeout_list->tail->next=NULL;
        //timeout_list->tail->next=NULL;
        //timeout_list->tail;
        timeout_list->size--;
        printf("time out queue dequeue 4!\n");
        if (B!=NULL){
            printf("dequeue msg with ticks [%d] from  timeoutq_dequeue!!\n",B->num_clock_ticks);
        }
       
    
    printf("time out queue dequeue done!\n");
    return B;
}

MsgEnv * RTX:: get_timeoutq_head(){
    return (timeout_list->head);
}

MsgEnv * RTX::get_timeoutq_tail(){
    return (timeout_list->tail);
}

PCB * RTX:: get_PCB(int target_pid){
    PCB * temp_PCB;
    int i=0;
    //printf("\n the PCB we want to find is %i\n",target_pid);
    while(i<Num_Proc){
        temp_PCB=PCB_list[i];
        if (temp_PCB->pid==target_pid)
        {
           //printf("\n the search PCB got the PCB %i\n",temp_PCB->pid);
           return temp_PCB;                            
        }
        else
        {i++;
        //printf("\n the search PCB go to the next PCB \n");
        }
    }
    //printf("\n the search PCB DID NOT got the PCB \n");
    return NULL;
}		

void RTX:: addTrace(MsgEnv* msg_env,int type){//sent=0, recieved=1
     if (type==0){
        for(int i=15;i>=0;i--)
            send_trace_buffer[i]=send_trace_buffer[i-1];
        send_trace_buffer->target_id =msg_env->target_pid;
        send_trace_buffer->sender_id =msg_env->sender_pid;
        send_trace_buffer->msg_type  =msg_env->type;
        send_trace_buffer->time_stamp=system_time;
     }
     if (type==1){
        for(int j=15;j>=0;j--)
            receive_trace_buffer[j]=send_trace_buffer[j-1];
        receive_trace_buffer->target_id =msg_env->target_pid;
        receive_trace_buffer->sender_id =msg_env->sender_pid;
        receive_trace_buffer->msg_type  =msg_env->type;
        receive_trace_buffer->time_stamp=system_time;
     }
}

void RTX::set_clock(int h, int m, int s){
     system_time=h*3600+m*60+s*1;
     return;
}

void RTX::clock_increment(){
    system_time++;
    return;
}

int RTX::get_time(){
    printf("RTX get_time function\n");
	return system_time;
}

void RTX::process_switch(){
    //printf("process_switch is running\n");
    prev_proc=cur_proc;
    
    cur_proc=rpq_dequeue();
    //printf("should switch from [%d] to [%d] \n",prev_proc->pid,cur_proc->pid);
    if(cur_proc==NULL){
        printf("ready queue is empty...\n");
    }
        
    //if(cur_proc->status!=I_Process)
    cur_proc->status=Executing;
    //printf("(process_switch)about to switch prev process [%d] to next process [%d]\n",prev_proc->pid,cur_proc->pid);
    context_switch(prev_proc,cur_proc);
    return;
}

void RTX::context_switch(PCB * from_proc,PCB * to_proc){
    //printf("context_switch is running\n");
    printf("switching prev process [%d] to next process [%d]\n",prev_proc->pid,cur_proc->pid);
    swapcontext(&(from_proc->proContext),&(to_proc->proContext));
    return;
}	

void RTX::atomic(bool on) {
    //Declear atomic_flag in rtx;
//set atomic_flag to 0;

   //printf("(when calling atomic) cur_proc is [%d]\n",cur_proc->pid);
    static sigset_t oldmask;
    sigset_t newmask;
    if (on && atomic_flag==0) {
          // printf("atomic is on and flag is 0\n");
       sigemptyset(&newmask);
       
       sigaddset(&newmask, SIGALRM); //the alarm signal
       //sigaddset(&newmask, SIGHUP);       
       //sigaddset(&newmask, SIGBUS);
       //sigaddset(&newmask, SIGSEGV);
       //sigaddset(&newmask, SIGILL);
       //sigaddset(&newmask, SIGQUIT);
       //sigaddset(&newmask, SIGABRT);
       //sigaddset(&newmask, SIGTERM);
       //sigaddset(&newmask, SIGINT); // the CNTRL-C
       sigaddset(&newmask, SIGUSR1); // the KB signal
       sigaddset(&newmask, SIGUSR2); // the CRT signal
       sigprocmask(SIG_BLOCK, &newmask, &oldmask);
       atomic_flag=1;
    }
    else {
    //unblock the signals
       if(atomic_flag==1){
      // printf("atomic off and flag is 1\n");
       sigprocmask(SIG_UNBLOCK, &oldmask, NULL);
       atomic_flag=0;
       }
    }
    //printf("(after calling atomic) cur_proc is [%d]\n",cur_proc->pid);
    return;
}


//the primitives!!	
int RTX::k_send_message(int dest_pid, MsgEnv *msg_envelope )//done
{//made some changes here, we only need one argument for this function since the envelope passed into the send message function will contain the target pid.
 //We need a way to get the PCB pointer from the pid. It should be easy because we know which process the message is going to be sent to
  // printf("in send_msg\n");
    if (msg_envelope==NULL){
       return success;
    }
    PCB *dest_PCB=get_PCB(dest_pid);
    //printf("k_send_msg got dest pcb\n");
      msg_envelope->sender_pid = cur_proc->pid;
      msg_envelope->target_pid = dest_pid;
      //printf("msg env processed in send_msg\n");
      //printf("\n the dest process for send is %i \n",dest_pid);
      //dest_PCB=get_PCB(dest_pid);//dest_PasCB is a pointer to the destination process
      //printf("\n search pcb complted\n");
      //printf("\n pid of the dest process is %i \n",dest_PCB->pid);
      dest_PCB->msgQ->enqueue(msg_envelope);//put msg onto msg Q of dest_PCB
      printf("after enqueue msg envelope to the dest PCB [%d]...\n"
              "the msgQ size is [%d]\n",dest_PCB->pid,dest_PCB->msgQ->getsize());
      if (dest_PCB->status == Blocked_On_Receive)//however, if destination process status=blocked on receive
    {
        dest_PCB->status=Ready;//set status to ready
        rpq_enqueue (dest_PCB);
        //printf("unblock process [%d] and enqueue to ready queue, \n",dest_pid);
        addTrace(msg_envelope,Type_Send);
    }
      
      
      //printf("\n msg inqueued\n");
 	
//printf("\nmsg received!\n");
return success;
}


MsgEnv * RTX:: k_receive_message()//done
{
 	//MsgEnv *msg_env;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
    //printf("(in k_receive)cur_porc is [%d]\n",cur_proc->pid);
    //printf("start receiving message\n");
    
 	MsgEnv *temp=NULL;
 	//printf("the size fo the msgQ on Process P is %s\n",PCB_list[ProcessP]->msgQ->getsize());
        while (temp==NULL){//cur_proc->msgQ->getsize()==0
            temp=cur_proc->msgQ->dequeue();
            if(temp!=NULL){
                addTrace(temp,Type_Receive);
                //printf("dequeue in recieve success\n");
                //printf("msg type is [%d]\n",temp->type);
                return temp;                
            }
            
            if(cur_proc->priority==I_Process){
                //process_switch();
                return temp;
            }
            else{
                printf("No message for process [%d]--> process is blocked\n",cur_proc->pid);
                //printf("(in receive)cur_porc is [%d]\n",cur_proc->pid);
                cur_proc->status=Blocked_On_Receive;
                //blkq_enqueue(Blocked_On_Receive,cur_proc);
                //printf("(in receive, after dequeue)cur_porc is [%d]\n",cur_proc->pid);
                //printf("process is in blocked queue now\n");
                //printf("switched to the other process!\n");
                process_switch();
            }            
        }        
}

MsgEnv * RTX:: k_request_msg_env(){
        //check if free envelope Q is empty
        while (free_env_Q->getsize()==0){
              //check if calling process is an Iproc. If so, return null without blocking
              if(cur_proc->priority==I_Process)
                  return NULL;
              //if not an Iproc, block invoking function and proccess switch 
              cur_proc->status=Blocked_On_Resource;
              blkq_enqueue(cur_proc);
              // blkq_enqueue(Blocked_On_Resource,cur_proc);
              //rtx.blkq_enqueue(Blocked_On_Resource,cur_proc);//Penglin needs to get this function working
              process_switch();   
        }
        //Change status in case process was running from blocked state
        //if (cur_proc->status==Blocked_On_Resource)
        //   cur_proc->status=Executing;
        
        //if no errors after error checking return a deQed MsgEnv
        //MsgEnv* envelope=rtx.free_env_Q->dequeue();//Penglin needs to get this function working
        
        MsgEnv* envelope=free_env_Q->dequeue();//filler until penglin's functions are complete
        return envelope;
}

int RTX:: k_release_msg_env(MsgEnv* Msg_env_ptr){
          //PCB* temp=blkq_dequeue();//Penglin
          
    PCB* temp;//filler until Penglin
   //if(blkq_getsize(Blocked_On_Resource)!=0){
    //    temp=blkq_dequeue(Blocked_On_Resource);
    if(blkq_getsize()!=0){
        temp=blkq_dequeue();    
        temp->status=Ready;
        rpq_enqueue(temp);
    }
    free_env_Q->enqueue(Msg_env_ptr);    
        
    
  //  if (temp){
      //       send_message(temp->pid,Msg_env_ptr);
             
     //        temp->status=Ready;
             //RTX.rpq_enqueue(temp);//Penglin
     //        return 0;
          
          //no process is blocked on msg env, so continue
          //rtx.free_env_Q->enqueue(Msg_env_ptr);//Penglin
          return success;
}

int RTX:: k_release_processor( )//done
{
    if(rpq_getsize()!=0){//if size of the ready is not 0
        if(cur_proc->priority!=I_Process){
            cur_proc->status=Ready;//set the status of the invoking process to ready
            rpq_enqueue(cur_proc);//enqueue the invoking process to ready queue
        }               
        process_switch();//select the next process as current process
    }
	//if there is no other process in the ready queue
//the invoking process will continue to run (do nothing but return sucess)
      return success;//indicate success
}

int RTX:: k_request_process_status( MsgEnv * msg_env_ptr ){
printf("k_request_process_status running \n");
    if(msg_env_ptr==NULL)
        return error1;
//create an array to store status and priority data
//first check ready process queue        
    PCB* temp;
    char status_array[Max_Env_Data]="PID Piority Status\n";
    char temp_char[Max_Env_Data];
    for (int i=0;i<Num_Proc;i++){
//save the process's ID, status, and priority into the array
        //printf("in loop ps!\n");
        temp=PCB_list[i];
        sprintf(temp_char,"%i   %i       %i\n",temp->pid,temp->priority,temp->status);
        strcat(status_array,temp_char); 
         // temp_char=char(temp->pid);
        //strcat(status_array,temp_char);
        //strcat(status_array,"   ");
        //temp_char=char(temp->priority);
        //strcat(status_array,temp_char);
        //strcat(status_array,"        ");
        //temp_char=char(temp->status);
        //strcat(status_array,temp_char);
        //strcat(status_array,"\n");
        
        //temp=temp->next;
        
    }
    strcpy(msg_env_ptr->msg_data,status_array);
        
        //printf("list status[%s]\n",msg_env_ptr->msg_data);
    return success;
}

int  RTX::k_terminate(){
	die(SIGINT);//invoke die() to terminate the KB, and CRT u-processes
	//exit(0);//use kill(linux command) to terminate the RTX, and the child processes end because the parent process is dead
        return 0;
}

int RTX::k_change_priority(int new_priority, int target_process_id){
    if((new_priority > 3) || (new_priority<0))
        return error1;
    PCB * target_pcb=get_PCB(target_process_id);
    if(target_pcb==NULL)
        return error1;
    switch(target_pcb->status){
        case I_Process:
            printf("I_proc priority cannot be changed \n");
            break;
        case Executing:
            target_pcb->priority=new_priority;
            break;
        case Ready:
            target_pcb=rpq_remqueue(target_pcb);
            target_pcb->priority=new_priority;
            rpq_enqueue(target_pcb);
            break;
        case Blocked_On_Receive:
            target_pcb->priority=new_priority;
            break;
        case Blocked_On_Resource:
            //target_pcb=blkq_remqueue(target_pcb->status,target_pcb);
            target_pcb=blkq_remqueue(target_pcb);
            target_pcb->priority=new_priority;
            //blkq_enqueue(target_pcb->status,target_pcb);
            blkq_enqueue(target_pcb);
            break;        
    }
    return success;
}

int RTX:: k_request_delay( int time_delay, int wakeupcode, MsgEnv * message_envelope )
{
        int d;
        printf("(request delay)cur_proc is  [%d]\n",cur_proc->pid);
        message_envelope->type = wakeupcode;
        message_envelope->num_clock_ticks = time_delay;
        //message_envelope->target_pid=Timer;
        d=k_send_message(Timer, message_envelope);
        return d;
}

int RTX::k_send_console_chars(MsgEnv *message_envolope)
{
//Place MsgEnv pointer and process ID to KB i_process
//Put process onto Blocked_MsgEnv blocked queue
    //PCB * crt_iproc=get_PCB(CRT);
    //crt_iproc->msgQ->enqueue(message_envolope);
    printf("send_console_char trying to send msg to crt\n");
    message_envolope->sender_pid=cur_proc->pid;
    message_envolope->target_pid=CRT;
    //int send_error=k_send_message(CRT,message_envolope);
    Display_Q->enqueue(message_envolope);
    //if (send_error==0){//if send success
        //check if CRT gets the data by checking the returned msg
      //  printf("message sent to CRT\n");
      //  if(ready_Q[2]->head!=NULL && ready_Q[2]->head->next!=NULL){
        //                printf("right now the ready queue pri 2 head is [%d] and head next is [%d]\n",ready_Q[2]->head->pid,ready_Q[2]->head->next->pid);
        //            }
        //message_envolope=k_receive_message();
        printf("call CRT handler\n");
        crt_handler(0);
        return success;
}

int RTX::k_get_console_chars(MsgEnv *message_envolope)
{
//Place MsgEnv pointer and process ID to KB i_process
//Put process onto Blocked_MsgEnv blocked queue
   // PCB * kb_iproc=get_PCB(KB);
   // kb_iproc->msgQ->enqueue(message_envolope);
    send_message(KB, message_envolope);
    //crt_handler(0);
    return 0;
    //blkq_enqueue(Blocked_On_Receive,cur_proc);
    //(not part of this function        )
    //User inputs via KB
    //KB process sends signal to KB Iprocess signifying msgenv is available
}

int RTX:: k_get_trace_buffers( MsgEnv * message_envelope){
      int i=0;
      for (int j=15;j>=0;j--){
         message_envelope->msg_data[i]=send_trace_buffer[j].target_id;
         i++;
         message_envelope->msg_data[i]=send_trace_buffer[j].sender_id;
         i++;
         message_envelope->msg_data[i]=send_trace_buffer[j].msg_type;
         i++;
         message_envelope->msg_data[i]=send_trace_buffer[j].time_stamp;
         i++;
      }
      for (int k=15;k>=0;k--){
         message_envelope->msg_data[i]=receive_trace_buffer[k].target_id;
         i++;
         message_envelope->msg_data[i]=receive_trace_buffer[k].sender_id;
         i++;
         message_envelope->msg_data[i]=receive_trace_buffer[k].msg_type;
         i++;
         message_envelope->msg_data[i]=receive_trace_buffer[k].time_stamp;
         i++;
      }
      return 0;
}

//public user API
int RTX::send_message(int dest_pid, MsgEnv *msg_envelope ){
    //printf("send message user side\n");
    int result;
    atomic(ON);
    //printf("send message user side\n");
    result=k_send_message(dest_pid, msg_envelope);
    atomic(OFF);
    return result;
}


MsgEnv * RTX:: receive_message(){
    //printf("(in receive)cur_porc is [%d]\n",cur_proc->pid);
    MsgEnv * result;
    atomic(ON);
    result=k_receive_message();
    atomic(OFF);
    return result;
}

MsgEnv * RTX:: request_msg_env(){
    MsgEnv * result;
    atomic(ON);
    result=k_request_msg_env();
    atomic(OFF);
    return result;
}

int RTX:: release_msg_env(MsgEnv* Msg_env_ptr){
    int result;
    atomic(ON);
    result=k_release_msg_env(Msg_env_ptr);
    atomic(OFF);
    return result;
}

int RTX:: release_processor( ){
    int result;
    atomic(ON);
    result=k_release_processor( );
    atomic(OFF);
    return result;
}

int RTX:: request_process_status( MsgEnv * msg_env_ptr ){
    int result;
    atomic(ON);
    result=k_request_process_status(msg_env_ptr );
    atomic(OFF);
    return result;
}

int  RTX::terminate(){
    int result;
    //atomic(ON);
    result=k_terminate();
    //atomic(OFF);
    return result;
}

int RTX::change_priority(int new_priority, int target_process_id){
    int result;
    atomic(ON);
    result=k_change_priority(new_priority,target_process_id);
    atomic(OFF);
    return result;
}

int RTX:: request_delay( int time_delay, int wakeupcode, MsgEnv * message_envelope ){
    int result;
    atomic(ON);
    result=k_request_delay(time_delay,wakeupcode,message_envelope );
    atomic(OFF);
    return result;    
}

int RTX::send_console_chars(MsgEnv *message_envolope){
    int result;
    atomic(ON);
    result=k_send_console_chars(message_envolope);
    atomic(OFF);
    return result;
}

int RTX:: get_console_chars(MsgEnv *message_envolope){
    int result;
    atomic(ON);
    result=k_get_console_chars(message_envolope);
    atomic(OFF);
    return result;
}

int RTX:: get_trace_buffers( MsgEnv * message_envelope){
    int result;
    atomic(ON);
    result=k_get_trace_buffers(message_envelope);
    atomic(OFF);
    return result;
}
